package com.ruoyi.act.module.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.pagehelper.PageInfo;
import com.ruoyi.act.module.domain.ActModel;
import com.ruoyi.act.module.service.IModelService;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

import static org.activiti.editor.constants.ModelDataJsonConstants.*;

@Service
public class ModelServiceImpl implements IModelService {

    @Autowired
    private RepositoryService repositoryService;


    @Override
    public byte[] getEditorSource(String modelId) {
        byte[] bytes =  repositoryService.getModelEditorSourceExtra(modelId);
        return bytes;
    }

    @Override
    public Model get(String modelId) {
        return repositoryService.getModel(modelId);
    }

    /**
     * 保存模型。 如果模型已经存在，则更新模型，否则创建新模型。
     * 参数：
     * model-要保存的模型，不能为null。
     *
     * @param actModel
     * @return
     */
    @Override
    public Model saveModel(ActModel actModel) {
        ObjectMapper objectMapper = new ObjectMapper();

        ObjectNode editorNode = objectMapper.createObjectNode();
        editorNode.put("id", "canvas");
        editorNode.put("resourceId", "canvas");
        ObjectNode stencilSetNode = objectMapper.createObjectNode();
        stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
        editorNode.putPOJO("stencilset", stencilSetNode);

        ObjectNode modelObjectNode = objectMapper.createObjectNode();

        modelObjectNode.put(MODEL_NAME, actModel.getName());
        modelObjectNode.put(MODEL_REVISION, actModel.getVersion() == null ? "1" : actModel.getVersion());
        modelObjectNode.put(MODEL_DESCRIPTION, actModel.getDesc() == null ? "" : actModel.getDesc());

        Model model = repositoryService.newModel();
        model.setMetaInfo(modelObjectNode.toString());
        model.setName(actModel.getName());
        model.setKey(actModel.getKey());
        model.setCategory(actModel.getCategory());
        model.setTenantId(actModel.getTenantId());

        repositoryService.saveModel(model);
        //保存模型的模型编辑器源
        //参数：
        //modelId –要删除的模型的ID，不能为null。 当为不存在的模型传递ID时，将忽略此操作。
        repositoryService.addModelEditorSource(model.getId(), editorNode.toString().getBytes(StandardCharsets.UTF_8));
        return model;
    }

    @Override
    public List<Model> findList(ActModel actModel) {
        ModelQuery modelQuery = repositoryService.createModelQuery();
        modelQuery.orderByLastUpdateTime().desc();

        if (StringUtils.isNotBlank(actModel.getName())) {
            modelQuery.modelNameLike("%" + actModel.getName() + "%");
        }
        if (StringUtils.isNotBlank(actModel.getKey())) {
            modelQuery.modelKey(actModel.getKey());
        }
        if (StringUtils.isNotBlank(actModel.getCategory())) {
            modelQuery.modelCategory(actModel.getCategory());
        }
        if (StringUtils.isNotBlank(actModel.getTenantId())) {
            modelQuery.modelTenantId(actModel.getTenantId());
        }

        List<Model> modelList = modelQuery.list();
        return modelList;
    }

    @Override
    public PageInfo<Model> findPge(ActModel actModel) {
        ModelQuery modelQuery = repositoryService.createModelQuery();
        modelQuery.orderByLastUpdateTime().desc();

        if (StringUtils.isNotBlank(actModel.getName())) {
            modelQuery.modelNameLike("%" + actModel.getName() + "%");
        }
        if (StringUtils.isNotBlank(actModel.getKey())) {
            modelQuery.modelKey(actModel.getKey());
        }
        if (StringUtils.isNotBlank(actModel.getCategory())) {
            modelQuery.modelCategory(actModel.getCategory());
        }
        if (StringUtils.isNotBlank(actModel.getTenantId())) {
            modelQuery.modelTenantId(actModel.getTenantId());
        }

        Integer pageNum = actModel.getPageNum() == null ? 0 : actModel.getPageNum() - 1;
        Integer pageSize = actModel.getPageSize() == null ? 10 : actModel.getPageSize();

        List<Model> modelList = modelQuery.listPage(pageNum * pageSize, pageSize);

        PageInfo<Model> pageInfo = PageInfo.of(modelList);
        pageInfo.setTotal(modelQuery.count());
        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);

        return pageInfo;
    }

    @Override
    public ByteArrayInputStream getModelEditorSource(String modelId, HttpServletResponse response) throws IOException {
        Model model = repositoryService.getModel(modelId);
        if (model == null) {
            return null;
        }

        JsonNode jsonNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(model.getId()));
        if (jsonNode == null) {
            return null;
        }

        BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
        if (!CollectionUtils.isEmpty(bpmnModel.getProcesses())) {
            byte[] bytes = new BpmnXMLConverter().convertToXML(bpmnModel);
            return new ByteArrayInputStream(bytes);
        }
        return null;
    }

    @Override
    public void deleteModel(String modelId) {
        repositoryService.deleteModel(modelId);
    }
}
